home *** CD-ROM | disk | FTP | other *** search
/ Acorn Risc Technologies StrongARM CD-ROM / Acorn Risc Technologies StrongARM CD-ROM.iso / ftp / documents / appnotes / 276_290 / 281c / Text
Encoding:
Text File  |  1995-06-06  |  45.1 KB  |  1,168 lines

  1. -----------------------------------------------------------------------------
  2. 26th April 1995
  3. -----------------------------------------------------------------------------
  4. Support Group Application Note
  5. Number: 281
  6. Issue:  0.01
  7. Author: NK
  8. -----------------------------------------------------------------------------
  9. Writing Toolbox Gadgets
  10. -----------------------------------------------------------------------------
  11. Notes: 
  12.  
  13. -----------------------------------------------------------------------------
  14. Applicable Hardware: Any RISC OS computer running RISC OS 3 (version 3.10)
  15.                      or later
  16.  
  17. Related Application Notes: 280
  18.  
  19.  
  20. -----------------------------------------------------------------------------
  21. Copyright (C) 1995 Acorn Computers Limited
  22.  
  23. Every effort has been made to ensure that the information in this leaflet is 
  24. true and correct at the time of printing. However, the products described in
  25. this leaflet are subject to continuous development and improvements and
  26. Acorn Computers Limited reserves the right to change its specifications at
  27. any time. Acorn Computers Limited cannot accept liability for any loss or
  28. damage arising from the use of any information or particulars in this
  29. leaflet. ACORN, ECONET and ARCHIMEDES are trademarks of Acorn Computers
  30. Limited.
  31. -----------------------------------------------------------------------------
  32. Support Group
  33. Acorn Computers Limited
  34. Acorn House
  35. Vision Park
  36. Histon
  37. Cambridge
  38. CB4 4AE                                                  
  39. -----------------------------------------------------------------------------
  40.  
  41.  
  42. Contents
  43. --------
  44.  
  45. Introduction
  46. A simple Gadget
  47. Creating and editing new Gadget types
  48. Modifying !ResTest
  49. More advanced Gadget features
  50. Composite Gadgets
  51. Redrawable Gadgets
  52. Registration
  53.  
  54. Appendices
  55.  
  56. GLIB and the Window module extensions
  57. Miscellaneous information
  58. Examples
  59.  
  60. Introduction
  61. ------------
  62.  
  63. This document assumes a familiarity with the RISC OS Toolbox Environment and
  64. writing RISC OS relocatable modules. Details of the Toolbox may be found in
  65. the 'User Interface Toolbox Manual' which is part of the Acorn C/C++ product
  66. (SKB78). All of the examples given within this document are written in C and
  67. Acorn encourages developers to use the C language to write new Modules,
  68. however it is possible to write them in assembler and the Appendix at the
  69. end of this document will describe the SWI calls that are necessary to
  70. interface to the environment.
  71.  
  72. This application note describes how new Gadgets may be added to the RISC OS
  73. Toolbox environment. The Window module (version 1.29 and above) has a number
  74. of SWIs that allow new Gadget types to be added to the environment at run
  75. time. A new Gadget type is implemented with a RISC OS relocatable module
  76. which registers itself with the Window module and is then called to perform
  77. various services when the Window module encounters a Gadget of this type.
  78.  
  79. Most of the document describes how one of these modules can be written. The
  80. remainder explains how to modify !ResEd and !ResTest to allow the new
  81. Gadget(s) to be created and tested and finally an Appendix defines the
  82. Window SWIs required and the C library which uses them (GLib).
  83.  
  84. A simple Gadget
  85. ---------------
  86. This section describes how a simple gadget (in this case a 'Tool' button
  87. that one might find on a Toolbar such as the drawing tools in !Draw) is
  88. implemented as a C relocatable module using GLib. It is essentially a sprite
  89. option button in that clicking on it with the mouse will change its state
  90. from one sprite to another. It will also raise a Toolbox event on the Gadget
  91. when the state changes.
  92.  
  93. The first thing to do is to write a public header file which defines the
  94. template for the Gadget type, the events associated with it and any other
  95. public information such as the valid flag bits. There should also be a
  96. private header to be used by the module which prototypes the handlers for
  97. instance. ToolButton.h
  98.  
  99. /*--------- Tool Button ---------- 
  100.  * ToolButton.h
  101.  */
  102.  
  103.  
  104. /* template definition */
  105.  
  106. typedef struct
  107. {   GadgetHeader hdr ;
  108.     char         *sprites;
  109.     int          type;
  110.     int          event;
  111. } ToolButton;
  112.  
  113. #define ToolButtonValidFlags             0xC0000000
  114.  
  115. /* tool button methods */
  116.  
  117. #define ToolButton_Base                  0x49d0
  118. /* none defined yet */
  119.  
  120. #define ToolButton_Type  (sizeof(ToolButton)) << 16    | ToolButton_Base
  121.  
  122. /* tool button events */
  123.  
  124. #define ToolButton_StateChanged          (GTest_00)
  125.  
  126. typedef struct
  127. {       ToolboxEventHeader hdr;
  128.         int                new_state;
  129. } ToolButtonStateChangedEvent;
  130.  
  131. #define ToolButton_StateChanged_Adjust  0x00000001
  132. #define ToolButton_StateChanged_Select  0x00000004
  133.  
  134. ToolBtnP.h
  135.  
  136. /*
  137.  * ToolBtnP.h
  138.  */
  139.  
  140. _kernel_oserror *toolbutton_add(ToolButton *template,int wimpw,int **icons,int **data);
  141. _kernel_oserror *toolbutton_mclick(int *handle,WimpMouseClickEvent *click,ObjectId win,int *claim);
  142.  
  143. After having set up a suitable CMHG file (in this case for a module GTest)
  144. the various Module handlers can be written. At module initialisation and on
  145. receiving the service call Service_WindowModuleStarting the GTest module
  146. needs to register itself with the Window module. Similarly at finalisation
  147. the module deregisters itself (Note the use of a finalisation handler rather
  148. than atexit).
  149.  
  150. The registration process works as follows: Any Gadget type has a set of
  151. 'features', which refer to the services that the module implementing it is
  152. capable of. In the example below the Toolbutton Gadget can be created,
  153. removed and can handle mouse clicks. This is identified by setting various
  154. bits in a Features Mask: Initially the mask is zero which implies that no
  155. features are defined for this type. By setting the add and mclick bits to
  156. PRIVATE_HANDLER it signifies that the module has handlers for adding and
  157. handling clicks on this type of Gadget. 
  158.  
  159. The remove bits are set to DEFAULT_HANDLER which means the Window module
  160. will handle all the actions associated with Gadget removal, ie. deleting
  161. icons, freeing memory etc. Note that this may only be used if the Gadget
  162. uses the GLib functions (or their SWI equivalent) for icon creation and
  163. memory allocation. The obvious benefit here is that less code requires to be
  164. written and removal of Gadgets is quicker as the Window module does not need
  165. to call out to another module. Note that not all feature bits can be set to
  166. DEFAULT_HANDLER, for instance, there is no default add_gadget handler. The
  167. possible values for each of the feature bits is described in the GLib
  168. appendix.
  169.  
  170. The only other type of handler is NO_HANDLER which implies that this module
  171. provides no facilities for this operation and that the Window module should
  172. do nothing either. In this simple case the method bits are zero (ie.
  173. NO_HANDLER) and so this module provides no methods.
  174.  
  175. The registration also tells the Window module what SWI to call out to and
  176. what flags (from the Gadget header such as the faded bit) are valid from
  177. this type of Gadget. The latter simplifies the Gadget adding handler.
  178.  
  179. from ModHdr
  180.  
  181. title-string:                   GTest
  182. help-string:                    Gadget_Test 0.01
  183.  
  184. initialisation-code:            GTest_init
  185. finalisation-code:              GTest_final
  186.  
  187. swi-chunk-base-number:          0x49d00
  188. swi-handler-code:               GTest_SWI_handler
  189. swi-decoding-table:             GTest,ToolButton
  190.  
  191. service-call-handler:           GTest_services 0x82881
  192.  
  193. from main.c
  194.  
  195. static void register_gadgets(void)
  196. {
  197.     FeatureMask features ;
  198.  
  199.     features.mask = 0;
  200.     features.bits.add    = PRIVATE_HANDLER;
  201.     features.bits.mclick = PRIVATE_HANDLER;
  202.     features.bits.remove = DEFAULT_HANDLER;
  203.     register_gadget_type(0,ToolButton_Type,ToolButtonValidFlags
  204.                  ,features.mask,GTest_ToolButton);
  205.  
  206. }
  207.    
  208. extern _kernel_oserror *GTest_init(char *cmd_tail, int podule_base, void *pw)
  209. {
  210.     IGNORE(cmd_tail) ;
  211.     IGNORE(podule_base);
  212.     IGNORE(pw);
  213.  
  214.     register_gadgets();
  215.     return NULL;
  216. }
  217.  
  218. extern void GTest_services(int service_number, _kernel_swi_regs *r, void *pw)
  219. {
  220.     IGNORE(pw) ;
  221.     IGNORE(r);
  222.  
  223.     switch (service_number)
  224.     {
  225.         Service_WindowModuleStarting: 
  226.         register_gadgets();
  227.                 break;
  228.         default:
  229.             break;
  230.     }
  231. }
  232.  
  233. extern _kernel_oserror *GTest_final (int fatal, int podule, void *pw)
  234. {
  235.     IGNORE(fatal) ;
  236.     IGNORE(podule);
  237.     IGNORE(pw);
  238.  
  239.     deregister_gadget_type(0,ToolButton_Type,GTest_ToolButton);
  240.     return NULL;
  241. }
  242.  
  243. The Window module will now SWI the GTest module whenever a Toolbutton Gadget
  244. is created or clicked on. The SWI handler is as follows...
  245.  
  246. extern _kernel_oserror *GTest_SWI_handler(int swi_no, _kernel_swi_regs *r, void *pw)
  247. {
  248.     _kernel_oserror *e = NULL;
  249.  
  250.     IGNORE(pw);
  251.  
  252.     switch (swi_no) {
  253.         case 0:
  254.                 switch (r->r[2]) {
  255.               case GADGET_ADD:
  256.                 e = toolbutton_add((ToolButton *) r->r[3],r->r[5],
  257.                 (int **) &(r->r[1]),(int **) &(r->r[0]));
  258.                 break;
  259.               case GADGET_MCLICK:
  260.                 e = toolbutton_mclick((int *) r->r[3],
  261.                 (WimpMouseClickEvent*) r->r[6], (ObjectId) r->r[4], &(r->r[1]));
  262.                 break;
  263.               default:
  264.                 break;
  265.            }
  266.            break;
  267.         default:
  268.            break;
  269.     }
  270.     return e;
  271. }
  272.  
  273. It simply calls the appropriate function according to the service required
  274. (given in R2 on entry to the SWI handler). The add and mouse click functions
  275. can be found in toolbutton.c:
  276.  
  277. static int my_icons[2] = {0,-1};
  278.  
  279. typedef struct {
  280.   int event;
  281.   ComponentId cid;
  282.   char state;
  283.   char type;
  284. } PrivateTButton;
  285.  
  286. extern _kernel_oserror *
  287. toolbutton_add(ToolButton *template,int wimpw,int **icons,int **data)
  288. {
  289.    WimpCreateIconBlock i;
  290.    PrivateTButton *tb;
  291.  
  292.    tb = (PrivateTButton *) mem_allocate(sizeof(PrivateTButton)+
  293.         string_length(template->sprites)+2);
  294.    if (!tb) return out_of_memory();
  295.    *data = (int *) tb;
  296.  
  297.    tb->event = template->event ? template->event : ToolButton_StateChanged;
  298.    tb->state = 0;
  299.    tb->cid   = template->hdr.component_id;
  300.    tb->type  = template->type;
  301.  
  302.    i.window_handle = wimpw;
  303.    i.icon.bbox = template->hdr.box;
  304.    i.icon.flags = WimpIcon_Text+WimpIcon_Sprite+WimpIcon_Indirected+
  305.                          (WimpIcon_ButtonType * ButtonType_Click);
  306.    i.icon.data.ist.buffer = "";
  307.    i.icon.data.ist.validation = (char *) (1+tb);
  308.    *i.icon.data.ist.validation = 's';
  309.    string_copy (1+i.icon.data.ist.validation,template->sprites);
  310.  
  311.    my_icons[0] = glib_create_icon(&i);
  312.    *icons = my_icons;
  313.    return NULL;
  314. }
  315.  
  316. The add handler is passed the template for the Gadget to be created and the
  317. wimp window handle (note that the SWI handler in main.c is also given the
  318. ObjectId for the window, but this is not generally required by Gadgets which
  319. are implemented using icons). From this information it is possible to create
  320. the Gadget - A data structure is allocated and filled in (Note that the
  321. memory is allocated in one chunk- this improves performance and reduces
  322. system memory fragmentation. It also means that a default remove handler may
  323. be used) and an icon is created. By using the GLib function to create an
  324. icon, initial fading and plotting of the Gadget (for !ResEd) will be handled
  325. on your behalf.
  326.  
  327. The add handler should fill in a static (as it is passed back) array with
  328. the list of icons that it has created terminated by -1. This allows the
  329. Window module to associate wimp events on an icon with a particular Gadget.
  330. The handler also returns a pointer to its data structure. This address is
  331. then passed to the other handlers which means that they do not have to worry
  332. about the more abstract Object/Component Ids and how these are associated
  333. with the Gadget's attributes.
  334.  
  335. Note the use of the string_length and string_copy functions (provided by the
  336. String32 library). These are equivalent to the strlen/strcpy functions in
  337. the standard C library but can cope with Ctrl terminated strings as the
  338. source. It is important that when a Gadget type is made available that it
  339. should be usable from any language such as BASIC in common with the rest of
  340. the Toolbox. It is conventional to store strings as Null terminated once
  341. inside the Toolbox, so that the String32 functions only need to be called
  342. for strings in Gadget templates and the method SWIs.
  343.  
  344. extern _kernel_oserror *
  345. toolbutton_mclick(int *handle,WimpMouseClickEvent *click,ObjectId win,int *claim)
  346. {
  347.    WimpSetIconStateBlock state;
  348.    ToolButtonStateChangedEvent event;
  349.    PrivateTButton *tb;
  350.  
  351.    tb = (PrivateTButton *) handle;
  352.    tb->state = 1- tb->state;
  353.  
  354.    state.window_handle = click->window_handle;
  355.    state.icon_handle   = click->icon_handle;
  356.    state.clear_word    = WimpIcon_Selected;
  357.    state.EOR_word      = WimpIcon_Selected*tb->state;
  358.  
  359.    wimp_set_icon_state(&state);
  360.  
  361.    event.hdr.flags      = 0;
  362.    event.hdr.event_code = tb->event;
  363.    event.hdr.size       = sizeof(ToolButtonStateChangedEvent);
  364.  
  365.    event.new_state      = tb->state;
  366.  
  367.    toolbox_raise_toolbox_event(0,win,tb->cid,(ToolboxEvent *) &event);
  368.  
  369.    *claim = 1;
  370.    return NULL;
  371. }
  372.  
  373. When the wimp sends a click event to the task, the Window module uses the
  374. icon lists (returned from Gadget creation) to determine which gadget the
  375. click occurred on. For one of the Toolbutton Gadgets this will result in the
  376. GTest module being SWIed. The click handler uses the private data (that was
  377. allocated in the add handler) to determine the state of the button and
  378. toggle it. It then raises a Toolbox event to inform the Client task of the
  379. change. Note that the ObjectId is passed through to the handler, but the
  380. ComponentId needs to be remembered in the data structure.
  381.  
  382. By 'claiming' the click, the Window module marks the Wimp mouse click event
  383. as having take place on the given component. Generally though, the client
  384. will only be interested in the high level event.
  385.  
  386. Creating and editing new Gadget types
  387. -------------------------------------
  388. !ResEd comes with an application !ResCreate which as its name implies
  389. creates resource files. It will create either a single object or a single
  390. gadget (contained in a Window object). When the 'Create gadget' option is
  391. chosen from the menu, the following dialogue appears:-
  392.                      
  393. <Insert Drawfiles.Figure1>
  394.  
  395. The 'Template name' is the the name of the Window object template to be
  396. created and the type is the allocated Gadget type (preceded by a '&' if
  397. entered in hex). The body size is the size of the gadget template, not
  398. including the header, so for the simple example above this would be 12.
  399. Comma separated lists of offsets should then be entered into the 'reference
  400. fields' - for the simple gadget '0' would be entered into the message
  401. reference writable (See the User interface toolbox manual for a description
  402. of references within templates). The template can then be saved and edited
  403. by !ResEd. Note that the Gadget will be created 'empty' so that strings and
  404. messages appear NULL and integer fields are zero.
  405.  
  406. Double Clicking on the 'unknown' Gadget results in a dialogue like the one
  407. below:-
  408.  
  409. <Insert Drawfiles.Figure2>
  410.  
  411. The various attributes of the Gadget are modified by using the offset number
  412. range to tell !ResEd what attribute is being edited and then !ResEd unfades
  413. the relevant writable below. In the Simple or Advanced example this means
  414. for offset zero that the message reference is unfaded. Moving the offset to
  415. four or eight unfades the integer field.
  416.  
  417. Modifying !ResTest
  418. ------------------
  419. Now that we have a new Gadget type, we'll want to try it out. After having
  420. created a Toolbutton Gadget with the modified !ResEd it can be loaded into
  421. !ResTest. Creating and showing its parent window will display a window
  422. containing a Toolbutton. Clicking on this will change its state from one
  423. sprite to another. Opening the event log though will show that an unknown
  424. event is being raised. !ResTest can be modified (without rebuilding) so that
  425. unknown events can become known and as with the standard Toolbox events,
  426. like Window_AboutToBeShown, Certain aspects of the event itself can also be
  427. displayed.
  428.  
  429. Two files control !ResTest's output: The 'Standard' file has tags for all
  430. the event codes, so we add the line: 
  431.  
  432. m00049D00:ToolButton_StateChanged 
  433.  
  434. In general this is just <mCCCCCCCC:string> and on encountering the given
  435. event code, !ResTest will print (if enabled) the string which is associated
  436. with that code via the file. The other useful file is TBlockMess, this
  437. allows the event block itself to be printed. To this we add the line: 
  438.  
  439. E49d00 "new state = %d" 4 2 
  440.  
  441. The '4 2' at the end means print the fourth word as an
  442. integer - looking at the ToolButton.h file will show that the new state is
  443. stored in the first word after the event block header (which is four words
  444. long). Any number of lines may be associated with each event code, eg.
  445. Draggable_DragEnded has four lines enabling the destination window, icon and
  446. coordinates to be printed. The syntax for each line is shown below:
  447.  
  448. Eccccc <format string> offset type [extra]     where:
  449.  
  450.  ccccc is the event code
  451.  <format string> is a printf like format string, but
  452.  Containing at most one % operator - see below.
  453.  offset is the offset from the start of the event block in either bytes or
  454. words depending on the type and [extra] is an optional parameter again
  455. depending on the type:-
  456.  
  457. <Insert Drawfiles.Figure3>
  458.  
  459. For example to print a string which starts at the fourth word of the event 
  460. block we would use:
  461.  
  462. Eccccc "The string is %s" 4 1                          
  463.  
  464. The equivalent C for such an event would be like this:-
  465.  
  466.         typedef struct {
  467.            ToolboxEventHeader hdr;
  468.            char               string[64];
  469.         } myevent;
  470.  
  471. To print a coordinate which starts at the fourth word of the event block we 
  472. would use:
  473.  
  474. Eccccc "Coordinate: x = %d" 4 2
  475. Eccccc "            y = %d" 5 2
  476.  
  477. The equivalent C for such an event would be like this:-
  478.  
  479.         typedef struct {
  480.            ToolboxEventHeader hdr;
  481.            int                x;
  482.            int                y;
  483.         } myevent;
  484.  
  485. And to print a value from 0-255 as a percentage which starts at the fourth 
  486. word of the event block we would use:
  487.  
  488. Eccccc "The value is %2.2f %%" 16 5 2.55
  489.  
  490. The equivalent C for such an event would be like this:-
  491.  
  492.         typedef struct {
  493.            ToolboxEventHeader hdr;
  494.            unsigned char      value;
  495.         } myevent;
  496.  
  497. More advanced Gadget features
  498. -----------------------------
  499. Once a Gadget has been created it is typical that an application will want
  500. to operate on it. In the Toolbox environment this is done via a Toolbox
  501. Method. Adding methods to a Gadget is fairly similar to providing the
  502. handlers for adding and clicking that were introduced in the simple Gadget
  503. example GTest. Again the relevant bits of the Feature mask (bits.method)
  504. need to be set to PRIVATE_HANDLER. The Window module will now SWI the module
  505. when a task tries to use a method on the Gadget. As an example GTest can be
  506. modified so that it has a method to change the sprites of a Toolbutton. The
  507. Appendix on GLib gives details on how the handler will be called. Handling
  508. fading is done in a similar way.
  509.  
  510. Some Gadgets feature attached objects, for example the ActionButton can have
  511. a 'Show Object' attached to it. This is done by putting the name of the
  512. attached object (ie. the name of the template from which is should be
  513. created) inside the Gadget template and then the Gadget add handler will
  514. create this object (using the GLib function create_object) and store its
  515. handle in the data structure. The Gadget is then free to show and hide the
  516. object. Note that when showing, the Gadget should be given as the parent
  517. component. Also when the Gadget is removed, it should delete any attached
  518. objects according to the recurse bit (see GLib appendix) with
  519. Toolbox_DeleteObject. This means that the default remove handler can not be
  520. used in this case.
  521.  
  522. If using glib_create_icon and mem_allocate, then the Window module will
  523. handle the plotting of Gadgets (for !ResEd) automatically. It is possible to
  524. specify a custom plot handler - this might be desirable if the Gadget is
  525. intricate and takes a long time to redraw. Again it is implemented by set
  526. the features mask bits and providing a suitable handler - the GLib appendix
  527. describes the call mechanism. It's worth noting that providing a plot
  528. handler will improve !ResEd's performance. A plot handler should check the
  529. faded bit of the Gadget template's flags and modify the plot accordingly -
  530. ordinarily, glib_create_icon will have taken care of this.
  531.  
  532. The plot handler is passed a template from which it should render the
  533. Gadget. Note that this template is the same as the one stored in the
  534. resource file that is used for creation. One important feature therefore is
  535. that the bounding box in the header is in work area coordinates. This will
  536. not be a problem if the Gadget's plot handler uses Wimp_PlotIcon to render a
  537. template, but for screen relative renderers, access to the window state is
  538. required. Although this information is private to !ResEd, a service call is
  539. raised as !ResEd enters its redraw loop to allow such renderers access to
  540. this information.
  541.  
  542. Gadgets which contain a writable element can have the focus set to them. For
  543. such a Gadget to belong to set of linked writables, it must have a set focus
  544. handler which should put the caret in the icon or Gadget which is writable.
  545. If the Gadget is faded, it should 'pass on' the focus to the next member of
  546. the list. The Glib appendix describes the calling parameters for this
  547. handler. It is also possible to move a Gadget after creation - there is a
  548. default handler for Gadgets that consist solely of icons, but for Gadgets
  549. that can be resized as well as moved or composite Gadgets (see below) a
  550. private handler should be provided if the Gadget_Move method is to be
  551. supported.
  552.  
  553. Some Gadgets will require other wimp events such as key presses, drag ended
  554. or even wimp messages to function. In these cases the extension module will
  555. need to register with the toolbox directly 'to express an interest'.
  556. Application note 280 describes the use of these SWIs as they are fundamental
  557. to writing Toolbox object modules. This note should be read as there are
  558. many subtle aspects to Toolbox filters and failure to comply can lead to
  559. unexpected behaviour and in particular poor performance. Composite Gadgets
  560. also require them and the example demonstrates this.
  561.  
  562. Composite Gadgets
  563. -----------------
  564. This section describes composite Gadgets - these are ones that are made up
  565. of other Gadgets, for example the StringSet and NumberRange Gadgets contain
  566. no icons and are implemented with other Gadgets. This results in less code
  567. duplication as the NumberRange for instance does not require a copy of the
  568. slider code. It is even possible to create Gadgets which consist both of
  569. icons and other Gadgets!
  570.  
  571. Writing Composite Gadgets is very similar to icon based ones except that
  572. Gadgets are created instead of icons and Toolbox events are used instead of
  573. mouse clicks. It is this latter aspect which adds to their complexity. In
  574. the same way as keypresses above, Toolbox filters are required to 'hear' the
  575. events on the underlying gadgets. GLib provides a simple interface to the
  576. Toolbox filters that should be sufficient for most Gadgets.
  577.  
  578. Redrawable Gadgets
  579. ------------------
  580. The Gadgets that have been discussed up to now consist of Icons or Gadgets
  581. that have been created. In other words the graphic or text that they depict
  582. are handled by the wimp. In some instances it is necessary to have a more
  583. complex graphic which can not be represented as text or a sprite and so
  584. requires an external source to redraw it. This can be achieved by catching
  585. wimp redraw requests in a PostFilter and entering a redraw loop. There are a
  586. number of aspects though which need considering with this approach:-
  587.  
  588.   - A Window containing such a Gadget will need auto-redraw switched off.
  589.   - The filter should (in wimp terms) claim the event as the client will 
  590.     not be expecting the redraw request.
  591.   - If the Client did want redraw requests on the window, ie. the window 
  592.     contains one of these gadgets and the client renders into the window, 
  593.     then this approach can not be used. In these cases the client would 
  594.     have to call the Gadget module from within its own redraw loop.
  595.  
  596. Type Registration
  597. -----------------
  598. Since Gadgets have a type, a method base and possibly an event code, up to
  599. three distinct numbers (or ranges of numbers) must be associated with each
  600. type. They must be distinct as there is no guarantee as to what combination
  601. of Gadgets will be available in any system. For the purposes of development
  602. the following ranges should be used:-
  603.  
  604.         GadgetType      0xssssffxx      where ssss is the size of the 
  605.                                         template and xx can be 00-ff
  606.         MethodBase      0x00ffxx00
  607.         EventBase       0x000ffxx0
  608.  
  609. Gadgets which are released outside an organisation MUST be registered with
  610. Acorn and in return official types and bases will be allocated. Composite
  611. Gadgets require a tag, but as these do not need to be distinct, they do not
  612. require registration. Acorn will however maintain a list.
  613.  
  614. GLib - The Gadget extensions Library
  615. ------------------------------------
  616. This section describes the GLib function calls that are available to Gadget
  617. extension modules, It also describes the underlying SWIs and service calls.
  618. Note SBZ is an abbreviation for 'Should be zero'.
  619.  
  620. Service calls
  621.  
  622. The Window module provides a number of service calls for various events.
  623. Generally, it is just the starting and dying calls that will be of interest.
  624.  
  625. Service_WindowModuleStarting    0x82881
  626.  
  627.         R1 = 0x82881
  628.  
  629. #define Service_WindowModuleStarting    (Window_SWIChunkBase + 1)
  630.  
  631. This service call is sent by the Window module when it starts up and is
  632. ready to receive SWI calls. On receipt of this, a Gadget extension module
  633. should register itself with the Window Module.
  634.  
  635. Service_WindowModuleDying       0x82882
  636.  
  637.         R1 = 0x82882
  638.  
  639. #define Service_WindowModuleDying       (Window_SWIChunkBase + 2)
  640.  
  641. This service call is sent by the Window module when it is finalising. On
  642. receipt of this call a module may need to clear up and free any memory that
  643. has been allocated, though of course it need not die itself. Note that any
  644. memory allocated with mem_allocate will already have been freed and should
  645. not be freed again.
  646.  
  647. Service_GadgetRegistered                0x82883
  648.  
  649.         R0 = type
  650.         R1 = 0x82883
  651.         R2 = SWI number of handler
  652.         R3 = feature mask
  653.  
  654. #define Service_GadgetRegistered        (Window_SWIChunkBase + 3)
  655.  
  656. This service call is sent by the Window module whenever a Gadget extension
  657. module registers itself.  R0 identifies what type is being registered with
  658. R2 and R3 giving details of how such Gadgets will be handled.. It might be
  659. useful to a module which relies on the existence of a particular Gadget
  660. type.
  661.  
  662. Service_GadgetDeregistered      0x82884
  663.  
  664.         R0 = type
  665.         R1 = 0x82884
  666.         R2 = SWI number of handler
  667.  
  668. #define Service_GadgetDeregistered      (Window_SWIChunkBase + 4)
  669.  
  670. This service call is sent by the Window module when a Gadget type has
  671. successfully been deregistered. It might be useful to a module which relies
  672. on the existence of a particular Gadget type. It is possible that an
  673. extension module may register/deregister several times, so a reference count
  674. should be used to determine if any handler is present.
  675.  
  676. Service_RedrawingWindow 0x44EC6
  677.  
  678.         R0 = window handle
  679.         R1 = 0x44EC6
  680.  
  681. #define Service_RedrawingWindow      (Toolbox_SWIChunkBase + 6)
  682.  
  683. This service call is sent (in particular) by !ResEd so that Gadget plot
  684. handlers can gain access to information about the window that !ResEd is
  685. currently updating.
  686.  
  687. Registration
  688. ------------
  689. When registering for a particular Gadget type a mask of features (with all
  690. reserved/unused bits zero) must be supplied:-
  691.  
  692. typedef struct {
  693.    int add:2,   can be PRIVATE_HANDLER or NO_HANDLER¹
  694.    remove:2,            can be PRIVATE_HANDLER, DEFAULT_HANDLER² or NO_HANDLER³
  695.    reserved0:2, SBZ
  696.    method:2,            can be PRIVATE_HANDLER or NO_HANDLER
  697.    reserved:2,  SBZ
  698.    mclick:2,    can be PRIVATE_HANDLER or NO_HANDLER
  699.    reserved2:4, SBZ
  700.    plot:2,              can be PRIVATE_HANDLER or DEFAULT_HANDLER
  701.    setfocus:2,  can be PRIVATE_HANDLER or NO_HANDLER
  702.    move:2,              can be PRIVATE_HANDLER, DEFAULT_HANDLER or NO_HANDLER
  703.    fade:2;              can be PRIVATE_HANDLER or NO_HANDLER
  704. } FT;
  705.  
  706.                 ¹Not useful
  707.                 ²Only if GLib mem_allocate and create_xxx used.
  708.                 ³Not a good idea as no clear up will happen
  709.  
  710. typedef union {
  711.    int mask;
  712.    FT  bits;
  713. } FeatureMask;
  714.  
  715. SWI Window_RegisterExternal     0x82885
  716.  
  717.   Entry:        R0 =    flags (SBZ)
  718.         R1 ->   types (see below)
  719.         R2 =    Gadget SWI number
  720.  
  721. types is an array of GadgetExtensionRecords, ie.:-
  722.  
  723.         offset  value
  724.         +0      type
  725.         +4      valid flags
  726.         +8      features mask
  727.         +12n    -1 (terminator)
  728.  
  729. or in C terms:-
  730.  
  731.         typedef struct {
  732.           int type;
  733.           int validflags;
  734.           FeatureMask features;
  735.         } GadgetExtensionRecord;
  736.  
  737.  Exit:  All registers preserved
  738.                   
  739. This SWI registers the new Gadget type(s) with the Window module. The given
  740. SWI number will be called whenever the Window module encounters the given
  741. Gadget type and the features mask indicates that there is a handler
  742. available. See the registration section on valid types.
  743.  
  744. Two C functions are provided for registration, one taking an array like the
  745. SWI and the other taking separate parameters enabling registration for a
  746. single type:-
  747.  
  748. extern _kernel_oserror *register_gadget_types
  749.                         (unsigned int flags,
  750.                          GadgetExtensionRecord *rec,
  751.                          int SWIno);
  752.  
  753. extern _kernel_oserror *register_gadget_type
  754.                         (unsigned int flags,
  755.                          int type,
  756.                          unsigned int valid,
  757.                          unsigned int mask,
  758.                          int SWIno);
  759.  
  760. Deregistration
  761.  
  762. SWI Window_DeregisterExternal   0x82886
  763.  
  764.   Entry:        R0 =    flags (SBZ)
  765.         R1 =    type of Gadget to deregister
  766.         R2 =    SWI that handled it.
  767.  
  768.  Exit:  All registers preserved
  769.  
  770. This SWI deregisters a Gadget type. Note that if a module dies without
  771. deregistering, the Window module will automatically deregister it on the
  772. next SWI call. This behaviour should not be relied on though - it is there
  773. to prevent unexpected behaviour with the rest of the system. A C function is
  774. provided by GLib:-
  775.  
  776. extern _kernel_oserror *deregister_gadget_type
  777.                         (unsigned int flags,
  778.                          int type,
  779.                          int SWIno);
  780.  
  781. Module support
  782.  
  783. SWI Window_SupportExternal      0x82887
  784.  
  785.   Entry:        R0 =    flags (SBZ unless otherwise stated)
  786.         R1 =    Reason code
  787.         R2...   Code specific
  788.  
  789.   Exit: depends on reason code
  790.  
  791. This SWI provides various function calls that are of use to extension modules.
  792.  
  793. CreateIcon (0)
  794.  
  795.   Entry:        R1 =    0 (CreateIcon)
  796.         R2 ->   wimp icon definition
  797.  
  798.   Exit: R0 =    Icon handle or -1 if failed to create
  799.  
  800. This call creates a wimp icon from the given definition except when the
  801. Window module is in 'plotting' mode. A C equivalent is available:
  802.  
  803. int glib_create_icon(WimpCreateIconBlock *i);
  804.  
  805. CreateObject (2)
  806.  
  807.   Entry:        R0 =    flags
  808.         R1 =    2 (CreateObject)
  809.         R2 ->   depends on flag bit 0:
  810.                         clear   R2-> template name
  811.                         set     R2-> in memory object definition
  812.  
  813.   Exit: R0 =    ObjectId or zero if failed to create
  814.  
  815. This call creates a toolbox object and returns its ObjectId. The reason for
  816. using this as opposed to toolbox_create_object (SWI Toolbox_CreateObject) is
  817. that the Window module first checks for plotting rather than creation mode.
  818. If the Gadget provides a plot handler, then it may safely use
  819. Toolbox_CreateObject SWI in its add handler.
  820.  
  821. CreateGadget (3)
  822.  
  823.   Entry:        R1 =    3 (CreateGadget)
  824.         R2 =    ObjectId (must be current ObjectId)
  825.         R3 ->   gadget definition
  826.         R4 =    tag (0x800 to 0xfff)
  827.  
  828.   Exit: R0 =    ComponentId or 0 if failed to create
  829.  
  830. This call, used for implementing composite gadgets, creates a gadget from
  831. the given template definition. The Window module generates a unique
  832. ComponentId for the gadget derived from the tag - It will be of the form
  833. 0x?????ttt. The use of a tag allows improved reaction to events on composite
  834. gadgets in that if a Composite Gadget creates all its Gadgets with tag 999,
  835. then its event routines can return immediately if the ComponentId's lower
  836. bits do not equal 999. Tags do not require registration, but it is worth
  837. advising Acorn so that where possible, clashes can be avoided. In order to
  838. receive Toolbox events, a module must register an interest in them - this is
  839. described in application note 280. A C equivalent is available:
  840.  
  841. int create_gadget(int o,int *i,int f);
  842.  
  843. MemAllocate (4)
  844.  
  845.   Entry:        R1 =    4 (MemAllocate)
  846.         R2 =    amount
  847.  
  848.   Exit: R0 =    pointer to memory or NULL
  849.  
  850. This call allocates memory from the Window modules allocator. A C equivalent
  851. is available:
  852.  
  853. void *mem_allocate(int amount);
  854.  
  855. MemFree (5)
  856.  
  857.   Entry:        R1 =    5 (MemFree)
  858.         R2 =    pointer
  859.  
  860.   Exit: All registers preserved
  861.  
  862. This call frees memory that was previously allocated by the Window modules
  863. allocator. A C equivalent is available:
  864.  
  865. void mem_free(void *tag);
  866.  
  867. MemExtend (6)
  868.  
  869.   Entry:        R1 =    6 (MemExtend)
  870.         R2 =    pointer
  871.         R3 =    change in size
  872.  
  873.   Exit: R0 =    pointer to memory of NULL if extend failed
  874.  
  875. This call reallocates memory that was previously allocated by the Window
  876. modules allocator. The change may be positive or negative to grow or shrink
  877. the block accordingly. Note that the pointer to the block may have to change
  878. and this is returned in R0.
  879.  
  880. C functions
  881.  
  882. GLib provides a number of functions that are useful for writing Gadgets,
  883. which are not provided by the Support SWI.
  884.  
  885.     void graphics_window (BBox *area)
  886.  
  887. This call sets the current graphics (ie clipping window) to the given
  888. bounding box by calling VDU 23. It is of use by Redrawable Gadget handlers
  889. and possibly plot handlers.
  890.  
  891.     BBox *intersection(BBox *one, BBox *two)
  892.  
  893. This call returns the bounding box that is the intersection between the two
  894. given boxes. Note that as this call returns the pointer to a static area,
  895. its contents will not persist over consecutive calls. If there is no
  896. intersection, then the returned pointer will be zero.
  897.  
  898. C interface to filters
  899. ----------------------
  900. For filters an event list is a pair array of event and class terminated by a
  901. -1. For no class, eg. wimp messages or wimp events a class of zero should be
  902. used. For example an event list for a toolbox event on a Window object might
  903. be {1 /* client event code */, Window_ObjectClass, -1} or for redraw events
  904. { Wimp_ERedrawWindow, 0 /* wimp window */, -1}.
  905.  
  906.     _kernel_oserror *add_task_interest(FilterTypes type, int *events, int SWI)
  907.  
  908. This function calls (if necessary) Toolbox_RegisterPostFilter (described in
  909. detail in application note 280) with the given list of events for the
  910. current task. The type can be one of GLib_ToolboxEvents (typically used for
  911. composite Gadgets), GLib_WimpEvents or GLib_WimpMessages. The SWI to call
  912. when matching this event pattern should also be given. The call should be
  913. made in the Gadget add handler and then GLib decides whether or not to make
  914. the call to the Toolbox according to a reference count - This ensures an
  915. efficient use of filters as registering multiple times can affect
  916. performance.
  917.  
  918.     _kernel_oserror *remove_task_interest(FilterTypes type, int *events)
  919.  
  920. This function decrements its reference count and then deregisters the
  921. Toolbox filter if necessary. It should be called un the Gadget remove
  922. handler - this obviously means that a default handler cannot be used for
  923. Gadgets that have registered an interest in events.
  924.  
  925. Note that only one list may be used per module per type of filter. This
  926. means that where more than one Gadget is implemented by a module and each
  927. Gadget requires toolbox events the relevant lists require combination. This
  928. is however a restriction of GLib and not the Toolbox.
  929.  
  930. When such a filter is called it will have the following parameters passed to
  931. it:-
  932.  
  933.   Entry:        R0 =    event code 
  934.         R1 ->   event block
  935.         R2
  936.         R3 ->   Id block for event
  937.  
  938.   Exit: R0 =    Claim state
  939.  
  940. The event code will be one of the Wimp event codes or 512 (Toolbox Event).
  941. The filter should process the event and set R0 as follows. If the filter was
  942. uninterested in the event or it has just used the information in the event
  943. (as a Composite Gadget might do and then raise a 'higher level' event) then
  944. R0 should be set to zero. If the Filter has updated the Id block (eg. set
  945. the Component Id) then +1 should be returned in R0, but note that for
  946. Gadgets this is a very unlikely use as it would generally break the
  947. philosophy of the toolbox. Finally setting R0 to -1 will claim the event (in
  948. wimp terms) so that it will not be seen by the client. This could be
  949. acceptable in the case of a keyboard shortcut for instance, but again
  950. generally events should be allowed through.
  951.  
  952. Other C functions
  953. -----------------
  954. Other functions within wimplib and toolboxlib are also useful, in particular
  955. wimp_delete_icon, wimp_create_icon (when glib_create_icon not used),
  956. wimp_plot_icon (for plot handlers - see below), toolbox_delete_object,
  957. toolbox_raise_toolbox_event etc. Note the Window_AddGadget method must not
  958. be used when writing composite Gadgets as the parent Window object may not
  959. have finished being created.
  960.  
  961. Handlers
  962. --------
  963. When the Gadget Module's SWI handler is called, R0 holds the flags (which
  964. are reason code specific), R1 the Gadget type and the reason code (in R2).
  965. The reason codes and register usage are described below. Note that if a
  966. handler needs to call another handler (eg. the mouse click handler calls the
  967. method handler), then this should be done directly inside the extension
  968. module and not through the Toolbox SWIs. It is however acceptable to make
  969. Toolbox SWIs for Gadgets of a different type.
  970.  
  971. GADGET_ADD (1)
  972.  
  973.   Entry:        R2 =    GADGET_ADD (1)
  974.         R3 ->   gadget template
  975.         R4 =    ObjectId of parent window
  976.         R5 =    Wimp window handle
  977.  
  978.   Exit: R0 =    Handle to use in future calls
  979.         R1 ->   icon list
  980.  
  981. On receiving this reason code an extension module should create the new
  982. gadget from the given data and return its icon list and private handle. The
  983. template will already have been checked for valid flags. Any attached
  984. objects (like the Click show objects attached to action buttons) should be
  985. created using the GLib calls.
  986.  
  987. GADGET_REMOVE (2)
  988.  
  989.   Entry:        R0 =    flags (bit 0 is recurse bit)
  990.         R2 =    GADGET_REMOVE (2)
  991.         R3 ->   private data
  992.  
  993.   Exit: All registers preserved
  994.  
  995. On receiving this reason code an extension module should remove the gadget.
  996. If the recurse bit is set then any attached objects such as Windows or Menus
  997. should not be removed. This is in common with the flag bit in the SWI
  998. Toolbox_DeleteObject.
  999.  
  1000. GADGET_FADE (3)
  1001.  
  1002.   Entry:        R2 =    GADGET_FADE (3)
  1003.         R3 ->   private data
  1004.         R4 =    state (non zero = fade)
  1005.         R5 =    ObjectId of window to which this Gadget belongs
  1006.  
  1007.   Exit: All registers preserved
  1008.  
  1009. On receiving this reason code an extension module should fade or unfade the
  1010. gadget, according to the value in R4. A Gadget will have been faded by the
  1011. client making a call to the Gadget_SetFlags method.
  1012.  
  1013. GADGET_METHOD (4)
  1014.  
  1015.   Entry:        R2 =    GADGET_METHOD (4)
  1016.         R3 ->   private data
  1017.         R4 ->   registers passed to Toolbox_ObjectMiscOp SWI
  1018.  
  1019.   Exit: Depends on Method
  1020.  
  1021. The window module raises this reason code when a task uses the
  1022. Toolbox_ObjectMiscOp SWI on a Gadget which is provided by an extension
  1023. module. R4 points to a register bank (in C terms this is the
  1024. _kernel_swi_regs type) which contains the values that the client passed to
  1025. the SWI. If any information is to be returned to the client then this bank
  1026. should be updated. Ie. to return a value in R0, do not set R0 to the value
  1027. but update the contents of the location pointed to by R4+0. Note that the
  1028. generic Gadget methods such as Gadget_SetFlags do not result in a call to
  1029. GADGET_METHOD.
  1030.  
  1031. GADGET_MCLICK (6)
  1032.  
  1033.   Entry:        R2 =    GADGET_MCLICK (6)
  1034.         R3 ->   private data
  1035.         R4 ->   wimp event block
  1036.  
  1037.   Exit: R1 = claim
  1038.  
  1039. The window module raises this reason code when an icon belonging to the
  1040. Gadget is clicked on. The event block in R4 is just like the one returned by
  1041. Wimp_Poll when an icon is clicked on. An extension module would typically
  1042. use this to update the state of the Gadget or return a 'high-level' Toolbox
  1043. Event. By setting R1 to be non-zero the Window module will update the tasks
  1044. ID block so that when the wimp mouse click event is delivered it is marked
  1045. as belonging to this Gadget. Although it is unlikely that the task will be
  1046. interested in the underlying event it should still be claimed. Possible
  1047. exceptions to this rule are when the menu mouse button is used - in this
  1048. case, not claiming the click (R1 = 0) passes the mouse click on which would
  1049. allow the Window's menu to be viewed. This is not true for a popup menu type
  1050. Gadget though.
  1051.  
  1052. It is also possible to claim the event entirely so that the task will not
  1053. see the mouse click. This is achieved by setting R1 to -1 on exit, but this
  1054. should be avoided as this does not fit the Toolbox model and so should only
  1055. be done in specialist cases.
  1056.  
  1057. GADGET_PLOT (9)
  1058.  
  1059.   Entry:        R2 =    GADGET_PLOT (9)
  1060.         R3 ->   gadget template definition
  1061.  
  1062.   Exit: All registers preserved
  1063.  
  1064. The window module raises this reason code when !ResEd is plotting Gadgets.
  1065. The extension module should use Wimp_PlotIcon or (Window_PlotGadget for
  1066. composite Gadgets) to display the Gadget which is defined by the template.
  1067.  
  1068. GADGET_SETFOCUS (10)
  1069.  
  1070.   Entry:        R0 =    flags, bit 0 = direction
  1071.         R2 =    GADGET_SETFOCUS (10)
  1072.         R3 ->   private data
  1073.  
  1074.   Exit: All registers preserved
  1075.  
  1076. When the Window module wishes to set the focus to a Gadget, this call will
  1077. be made. The direction signals whether to set the focus to the before of
  1078. after Gadget in the event of this Gadget being faded. Care should be taken
  1079. when 'passing on' the focus as an infinite loop will be entered if all
  1080. members of the list are faded. Gadgets which are composite and consist of a
  1081. writable Gadget do not need to worry about this and should just set focus to
  1082. their writable without checking their faded status, assuming that the before
  1083. and after fields of the underlying writable have been set.
  1084.  
  1085. GADGET_MOVE (11)
  1086.  
  1087.   Entry:        R2 =    GADGET_MOVE (11)
  1088.         R3 ->   private data
  1089.         R4 =    wimp window handle
  1090.         R5 ->   new bounding box
  1091.         R6 =    window ObjectId
  1092.  
  1093.   Exit: All registers preserved
  1094.  
  1095. This call is made when the Gadget_Move method is applied to a Gadget. A
  1096. composite gadget must supply a handler if it is going to be moved after
  1097. creation as the default handler can only move the icons which belong
  1098. directly to a Gadget. It is also of use if the Gadget supports resizing -
  1099. the default mover will only move by an offset as it generally does not know
  1100. how to handle and change in the size of the bounding box.
  1101.  
  1102. GADGET_POSTADD (12)
  1103.  
  1104. This call is beyond the scope of this document.
  1105.  
  1106. GADGET_???? (?)
  1107.  
  1108. Over time more handlers may become available and so the SWI handler should
  1109. not assume that only the handlers it has requested will result in a call
  1110. out. For a handler in C this would result in nothing being done by the
  1111. default case.
  1112.  
  1113. Miscellaneous Information
  1114. -------------------------
  1115.  
  1116. Hints & tips
  1117. ------------
  1118. Some thought should go into how different Gadgets are grouped together into
  1119. modules. On the one hand adding more and more modules can affect system
  1120. performance due to an increase in the number of SWI handlers and service
  1121. call handlers. However, memory will be wasted by combining a popular Gadget
  1122. with a set of Gadgets that are hardly used or are very specific to a
  1123. particular application.
  1124.  
  1125. It is also worth considering whether a new Gadget is indeed a new Gadget or
  1126. just a variant of an existing one - This is particularly important when it
  1127. comes to maintainability of an interface as a Gadget cannot be converted
  1128. into a different type, but it can have its properties modified. An example
  1129. of this distinction could be the Labelled box Gadget. If this were two
  1130. Gadget types (one for sprite labels and one for text labels) then it would
  1131. be harder to maintain if the designer changed their mind as to whether they
  1132. wanted a sprite or text.
  1133.  
  1134. Limitations
  1135. -----------
  1136. Early versions of the Window module have some faults which may affect the
  1137. behaviour of the extension system:-
  1138.  
  1139. Fault                                      Comment               Fixed in  
  1140.               
  1141. GADGET_POSTADD calls raised         Can be safely ignored          1.31
  1142.  
  1143. Default GADGET_MOVE will not work   Need to provide PH and call    1.31
  1144.                                     glib_move_gadget
  1145.                                  
  1146. Invalid flags can cause data abort  Either set valid flags to -1   1.31
  1147.                                     and check in add handler or 
  1148.                                     ignore - for a valid gadget 
  1149.                                     this will not happen.                 
  1150.  
  1151. Examples
  1152. --------
  1153. A number of examples are supplied with this application note. They are not
  1154. intended to be used as complete Gadgets in the same way as those supplied
  1155. with the Toolbox and Acorn reserves the right not to support them or even
  1156. reuse the types. No guarantee is made as to how robust or complete they are
  1157. and Acorn can not be held responsible if code within the examples is copied
  1158. and breaks.
  1159.  
  1160. The Simple Gadget is a 'Tool Button' and this is developed into the Advanced
  1161. Gadget which adds methods.
  1162.  
  1163. The Composite Gadget implements a 'Radio Group' - a labelled box with radio
  1164. buttons inside.
  1165.  
  1166. The Combined example shows how both Gadget types are implemented as one
  1167. module.
  1168.